#!/usr/bin/env python
# Create: 2018/10/18
__author__ = '749B'
"""把密码进行编码后保存，防窥屏"""

import argparse
import base64
import getpass
import random
import string
import sys

PYCHARM_NAME = "PyCharm 2017.3.3"
b64alphabet = string.digits + string.ascii_letters + r'+/'


def check_pycharm(name):
    """getpass无法在pycharm里使用
    检查不能用pycharm启动
    """
    for i in sys.path:
        if name in i:
            raise Exception("请使用终端来执行")


def b64encode_p(s, altchars=None, min_len=64, max_len=0xffff):
    """自定义加密
    字符串长度不足min_len，则随机生成字符串补足
    随机生成一个偏移量，把整个字符串，报告补足的一起做一个偏移
    把偏移的值和原始字符串长度转成4位16进制，拼接到末尾
    基于上面的4位显示，原生字符串长度不能超过65535
    最后把所有的内容进行base64加密
    """
    if len(s) > max_len:
        raise Exception("字符串长度过长，不应超过%d" % max_len)
    s_len = '{0:0>4x}'.format(len(s))  # 初始字符串长度，换算成16进制字符串，前面补0
    fill_len = max(min_len - len(s), 0)
    fill_str = ''.join(random.choices(b64alphabet, k=fill_len)) if fill_len else ''
    s += fill_str.encode()
    drift = random.randint(0, len(s) - 1)
    d_len = '{0:0>4x}'.format(drift)
    s = s[drift:] + s[:drift] + d_len.encode() + s_len.encode()
    return base64.b64encode(s, altchars)


def b64encode_str(str):
    """传入字符串，加密返回字符串"""
    s = b64encode_p(str.encode())
    return s.decode()


def b64decode_p(s, altchars=None, validate=False):
    """对应的还原解密方法"""
    s = base64.b64decode(s, altchars, validate)
    s, drift, s_len = s[:-8], s[-8: -4], s[-4:]
    drift = int(drift, base=16)
    s_len = int(s_len, base=16)
    return (s[(0 - drift):] + s[:(0 - drift)])[:s_len]


def b64decode_str(str):
    """传入字符串，解码返回字符串"""
    s = b64decode_p(str.encode())
    return s.decode()


def test():
    """调试方法，可以用来测试"""
    check_pycharm(PYCHARM_NAME)
    # 加密操作
    password = getpass.getpass()
    print("输入内容：", password)
    ciphertext = b64encode_p(password.encode())
    print("生成密文：")
    print(ciphertext.decode())
    # 解密操作
    plaintext = b64decode_p(ciphertext)
    print("还原明文：", plaintext.decode())


def show():
    """将编码后的字符打印到终端"""
    check_pycharm(PYCHARM_NAME)
    password = getpass.getpass()
    ciphertext = b64encode_p(password.encode())
    print("生成密文：")
    print(ciphertext.decode())


def file(file="password"):
    """通过对话输入用户名和密码，然后保存到文件"""
    check_pycharm(PYCHARM_NAME)
    username = input("用户名：")
    password = getpass.getpass("密码：")
    ciphertext = b64encode_p(password.encode())
    _password = ciphertext.decode()
    with open(file, 'w') as f:
        f.write(username + '\n')
        f.write(_password + '\n')
    print("生成文件", file)


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('mode', help="help: 查看运行模式", choices=list(actions), nargs='?')
    return parser.parse_args()


def help():
    """打印运行模式的帮助"""
    for k, v in actions.items():
        print(k, '\t', v.__doc__.split()[0])


def run():
    """执行file模式，参数都默认"""
    file()


actions = {
    'run': run,
    'help': help,
    'test': test,
    'show': show,
    'file': file,
}

if __name__ == '__main__':
    args = parse_args()
    default_mode = 'help'
    mode = args.mode or default_mode
    func = actions[mode]
    func()





